# pyhanzi
# 生成田字格汉字的图片
import os
import math
from typing import List
import click
from PIL import Image, ImageDraw, ImageFont
from yaspin import yaspin, Spinner

currrent_dir = (os.path.dirname(__file__)
                if "__file__" in locals() else os.getcwd())

# 边距的x坐标
OFFSET_X = 60
# 边距的y坐标
OFFSET_Y = 45
# 列宽
WIDTH = 116
# 行高
HEIGHT = 114.4
# 绘制的字体颜色
DARK = (0, 0, 0)

class ImgTextBrush(object):
    '''
    图片文字绘制画笔
    '''

    '''
    初始化

    :param tpl_img_file_path: 模板图片文件路径
    :param ttf_file_path: 字体ttf文件路径
    :param font_size: 绘制的文字的字号
    :param font_color_rgb: 绘制的文字的字体颜色
    :return: None
    '''
    def __init__(self, tpl_img_file_path: str, ttf_file_path: str, font_size: int, font_color_rgb: tuple = (0, 0, 0)):
        # 图片模板文件路径
        self.__tpl_img_file_path = tpl_img_file_path
        # 文字的字体、字号
        self.__font = ImageFont.truetype(ttf_file_path, font_size)
        # 文字的字体颜色
        self.__font_color_rgb = font_color_rgb


    '''
    绘制单个文字

    :param char: 单个文本
    :param start_idx: 绘制文本的起始坐标点坐标
    :return: 绘制了文本的图片对象
    '''
    def __draw_single_char(self, char: str, start_idx: tuple = (0, 0)):
        # 加载模板图片
        img = Image.open(self.__tpl_img_file_path)
        # 创建画笔
        brush = ImageDraw.Draw(img)
        # 往模板图片绘制单个文字
        brush.text(start_idx, char, self.__font_color_rgb, self.__font)
        return img

    '''
    合并多个相同宽、高的图片，从左到右依次合并

    :param imgs: 图片对象列表
    :return: 合并后的图片对象
    '''
    def __merge_imgs(self, imgs: List):
        size = len(imgs)
        img0 = imgs[0]
        width = img0.width
        height = img0.height
        # 单位宽度偏移量
        offset = width - 20
        
        # 目标图片尺寸
        target_shape = (width + (size - 1) * offset, height)
        # 创建背景空白图片
        background = Image.new('RGBA', target_shape, (0,0,0,0,))
        for idx, img in enumerate(imgs):
            background.paste(img, (idx * offset, 0))

        return background
    
    '''
    往图片上写文字，并保存为图片文件

    :param text: 要绘制的文本
    :param output_img_file_path: 输出的图片文件的路径
    :param start_idx: 绘制单个文本在模板图片中的起始坐标点坐标
    :param output_mode: 输出模式，默认为合并模式（"M"），只输出一个图片；也可指定为单字模式（"S"），表示一个字输出一个图片；还可指定为多行模式（"L"），表示一行输出一个图片
    :return: None
    '''
    def draw(self, text: str, output_img_file_path: str, start_idx: tuple = (0, 0), output_mode: str = 'M'):
        file_prefix = output_img_file_path.split('.')[0]
        file_postfix = output_img_file_path.split('.')[1]
        if output_mode == 'M':
            # 获取每个单字的图片
            imgs = []
            for char in text:
                if not char.isspace():
                    img = self.__draw_single_char(char, start_idx)
                    imgs.append(img)
            # 合并图片
            merged_img = self.__merge_imgs(imgs)
            # 保存为最终图片
            merged_img.save(f'{file_prefix}_{text}.{file_postfix}')
        elif output_mode == 'S':
            for char in text:
                if not char.isspace():
                    img = self.__draw_single_char(char, start_idx)
                    img.save(f'{file_prefix}_{char}.{file_postfix}')
        elif output_mode == 'L':
            # TODO 考虑\r\n和\r
            lines = text.split('\n')
            for line_idx, line in enumerate(lines):
                line = line.strip()

                # 获取每个单字的图片
                imgs = []
                for char in line:
                    if not char.isspace():
                        img = self.__draw_single_char(char, start_idx)
                        imgs.append(img)
                        # 合并图片
                        merged_img = self.__merge_imgs(imgs)
                        # 保存为最终图片
                        merged_img.save(f'{file_prefix}_line_{line_idx}_{line}.{file_postfix}')
        else:
            print('Invalid output_mode!')
                    
        
@click.command()
# 文本文件名
@click.option("--input_text_file", prompt="请输入文本文件名", default="text.txt", help="指定文本文件名")
# 字体文件名
@click.option("--ttf_file", prompt="请输入字体文件名", default="fonts/kaiti_GB2312.ttf", help="指定字体文件名")
# 模板图片文件
@click.option("--tpl_img_file_path", prompt="请输入模板图片文件名", default="migrid_tpl_200x200.png", help="指定模板图片文件名")
# 字体大小
@click.option("--font_size", prompt="请输入字体大小", default=135, help="指定字体大小")
# 输出图片文件路径
@click.option("--output_img_file_path", prompt="请输入输出图片文件路径", default="outputs/output.png", help="指定输出图片文件路径")
# 输出模式
@click.option("--output_mode", prompt="请输入输出模式（M：合并模式（默认），S：单字模式，L：多行模式）", default="L", help="指定输出模式（M：合并模式（默认），S：单字模式，L：多行模式）")
def main(input_text_file, ttf_file, tpl_img_file_path, font_size, output_img_file_path, output_mode):
    # 读取文本文件内容
    with open(input_text_file, 'r', encoding='utf-8') as f:
        text = f.read().strip()

    # 创建画笔
    tpl_img_file_path = tpl_img_file_path
    ttf_file_path = ttf_file
    font_size = font_size
    font_color_rgb = (0, 0, 0)
    start_idx = (30, 35)
    brush = ImgTextBrush(tpl_img_file_path, ttf_file_path, font_size, font_color_rgb)
    
    # 绘制文本、生成图片
    with yaspin(text="正在绘制汉字...", color="green") as spinner:        
        brush.draw(text, output_img_file_path, start_idx, output_mode)
        
        # 绘制完毕提示
        spinner.text = "绘制完成!"
        spinner.ok("√")

if __name__ == "__main__":
    main()

